package Thread;

/*
 * 多线程并发安全问题
 * 当多个线程并发操作同一临街资源，由于线程切换实际不确定， 导致执行顺序出现混乱从而导致程序不良后果
 * 临界资源：操作该资源的完成过程同一时刻只能被单一线程进行
 * */
public class SyncDemo {
    public static void main(String[] args) {
        Table table = new Table();
        Thread t1 = new Thread() {
            @Override
            public void run() {
                while (true) {
                    int bean = table.getBeans(); //获取当前豆子编号
                    Thread.yield();
                    System.out.println(getName() + ":" + bean); //通过getNmae 方法获取当前线程名称
                }
            }
        };

        Thread t2 = new Thread() {
            @Override
            public void run() {
                while (true) {
                    int bean = table.getBeans(); //获取当前豆子编号
                    Thread.yield();
                    System.out.println(getName() + ":" + bean); //通过getNmae 方法获取当前线程名称
                }
            }
        };

        //启动线程
        t1.start();
        t2.start();
    }
}

class Table {
    private int beans = 20; //桌子上的豆子

    /*
     * 使用synchronized关键字可以修饰方法
     * synchronized关键字的作用
     * synchroized关键字所修饰的方法 可以有效的解决并发安全问题
     * 尽量实现并发执行:多个线程有先后顺序的执行
     *
     * 如当前 Thread-0在使用getBeans方法是 当前的getBeans方法是被上锁的
     * 当Thread-0调用完getBeans方法后会将此方法解锁
     * 然后再由 正在排队的 Thread-1,Thread-2.....来调用此方法
     *
     * */
    public synchronized int getBeans() {//从桌子上获取豆子并返回编号
        if (beans == 0) {
            //当beans等于0时 此处向调用此方法的位置抛出异常
            throw new RuntimeException("桌子上没豆子啦");
        }

        Thread.yield(); //此静态方法就是当前线程主动放弃本次剩余的时间片，

        return beans--; //返回当前beans的值，并且在返回后自减一
    }
}
